<?php
/**
 * SocialEngine
 *
 * @category   Application_Core
 * @package    Fields
 * @copyright  Copyright 2006-2010 Webligo Developments
 * @license    http://www.socialengine.net/license/
 * @version    $Id: Standard.php 8076 2010-12-17 01:09:34Z john $
 * @author     John
 */

/**
 * @category   Application_Core
 * @package    Fields
 * @copyright  Copyright 2006-2010 Webligo Developments
 * @license    http://www.socialengine.net/license/
 * @author     John
 */
class Fields_Form_Standard extends Engine_Form {
	/* Custom */
	
	protected $_item;
	
	protected $_processedValues = array ();
	
	protected $_topLevelId;
	
	protected $_topLevelValue;
	
	protected $_isCreation = false;
	
	// Add custom element paths?
	public function __construct($options = null) {
		Engine_FOrm::enableForm ( $this );
		self::enableForm ( $this );
		
		parent::__construct ( $options );
	}
	
	public static function enableForm(Zend_Form $form) {
		$form->addPrefixPath ( 'Fields_Form_Element', APPLICATION_PATH . '/application/modules/Fields/Form/Element', 'element' );
	}
	
	/* General */
	
	public function getItem() {
		return $this->_item;
	}
	
	public function setItem(Core_Model_Item_Abstract $item) {
		$this->_item = $item;
		return $this;
	}
	
	public function setTopLevelId($id) {
		$this->_topLevelId = $id;
		return $this;
	}
	
	public function getTopLevelId() {
		return $this->_topLevelId;
	}
	
	public function setTopLevelValue($val) {
		$this->_topLevelValue = $val;
		return $this;
	}
	
	public function getTopLevelValue() {
		return $this->_topLevelValue;
	}
	
	public function setIsCreation($flag = true) {
		$this->_isCreation = ( bool ) $flag;
		return $this;
	}
	
	public function setProcessedValues($values) {
		$this->_processedValues = $values;
		$this->_setFieldValues ( $values );
		return $this;
	}
	
	public function getProcessedValues() {
		return $this->_processedValues;
	}
	
	public function getFieldMeta() {
		return Engine_Api::_ ()->fields ()->getFieldsMeta ( $this->getItem () );
	}
	
	public function getFieldStructure() {
		// Let's allow fallback for no profile type (for now at least)
		if (! $this->_topLevelId || ! $this->_topLevelValue) {
			$this->_topLevelId = null;
			$this->_topLevelValue = null;
		}
		return Engine_Api::_ ()->fields ()->getFieldsStructureFull ( $this->getItem (), $this->_topLevelId, $this->_topLevelValue );
	}
	
	// Main
	

	public function generate() {
		$struct = $this->getFieldStructure ();
		
		$orderIndex = 0;
		
		foreach ( $struct as $fskey => $map ) {
			$field = $map->getChild ();
			
			// Skip fields hidden on signup
			if (isset ( $field->show ) && ! $field->show && $this->_isCreation) {
				continue;
			}
			
			// Add field and load options if necessary
			$params = $field->getElementParams ( $this->getItem () );
			
			//$key = 'field_' . $field->field_id;
			$key = $map->getKey ();
			
			// If value set in processed values, set in element
			if (! empty ( $this->_processedValues [$field->field_id] )) {
				$params ['options'] ['value'] = $this->_processedValues [$field->field_id];
			}
			
			if (! @is_array ( $params ['options'] ['attribs'] )) {
				$params ['options'] ['attribs'] = array ();
			}
			
			// Heading
			if ($params ['type'] == 'Heading') {
				$params ['options'] ['value'] = Zend_Registry::get ( 'Zend_Translate' )->_ ( $params ['options'] ['label'] );
				unset ( $params ['options'] ['label'] );
			}
			
			// Order
			// @todo this might cause problems, however it will prevent multiple orders causing elements to not show up
			$params ['options'] ['order'] = $orderIndex ++;
			
			$inflectedType = Engine_Api::_ ()->fields ()->inflectFieldType ( $params ['type'] );
			unset ( $params ['options'] ['alias'] );
			unset ( $params ['options'] ['publish'] );
			$this->addElement ( $inflectedType, $key, $params ['options'] );
			
			$element = $this->getElement ( $key );
			
			if (method_exists ( $element, 'setFieldMeta' )) {
				$element->setFieldMeta ( $field );
			}
			
			// Set attributes for hiding/showing fields using javscript
			$classes = 'field_container field_' . $map->child_id . ' option_' . $map->option_id . ' parent_' . $map->field_id;
			$element->setAttrib ( 'class', $classes );
			
			//
			if ($field->canHaveDependents ()) {
				$element->setAttrib ( 'onchange', 'changeFields(this)' );
			}
			
			// Set custom error message
			if ($field->error) {
				$element->addErrorMessage ( $field->error );
			}
			
			if ($field->isHeading ()) {
				$element->removeDecorator ( 'Label' )->removeDecorator ( 'HtmlTag' )->getDecorator ( 'HtmlTag2' )->setOption ( 'class', 'form-wrapper-heading' );
			}
		}
		
		$this->addElement ( 'Button', 'submit', array ('label' => 'Save', 'type' => 'submit', 'order' => 10000 ) );
	}
	
	public function saveValues() {
		// An id must be set to save data (duh)
		if (is_null ( $this->getItem () )) {
			throw new Exception ( "Cannot save data when no identity has been specified" );
		}
		
		// Iterate over values
		$values = Engine_Api::_ ()->fields ()->getFieldsValues ( $this->getItem () );
		
		$fVals = $this->getValues ();
		if ($this->_elementsBelongTo) {
			if (isset ( $fVals [$this->_elementsBelongTo] )) {
				$fVals = $fVals [$this->_elementsBelongTo];
			}
		}
		
		foreach ( $fVals as $key => $value ) {
			$parts = explode ( '_', $key );
			if (count ( $parts ) != 3)
				continue;
			list ( $parent_id, $option_id, $field_id ) = $parts;
			
			// Whoops no headings
			if ($this->getElement ( $key ) instanceof Engine_Form_Element_Heading) {
				continue;
			}
			
			// Array mode
			if (is_array ( $value ) || $this->getElement ( $key )->isArray ()) {
				
				// Lookup
				$valueRows = $values->getRowsMatching ( array ('field_id' => $field_id, 'item_id' => $this->getItem ()->getIdentity () ) );
				
				// Delete all
				foreach ( $valueRows as $valueRow ) {
					$valueRow->delete ();
				}
				
				// Insert all
				$indexIndex = 0;
				if (is_array ( $value ) || ! empty ( $value )) {
					foreach ( ( array ) $value as $singleValue ) {
						$valueRow = $values->createRow ();
						$valueRow->field_id = $field_id;
						$valueRow->item_id = $this->getItem ()->getIdentity ();
						$valueRow->index = $indexIndex ++;
						$valueRow->value = $singleValue;
						$valueRow->save ();
					}
				}
			} 

			// Scalar mode
			else {
				// Lookup
				$valueRow = $values->getRowMatching ( array ('field_id' => $field_id, 'item_id' => $this->getItem ()->getIdentity (), 'index' => 0 ) );
				
				// Remove value row if empty
				if (empty ( $value )) {
					if ($valueRow) {
						$valueRow->delete ();
					}
					continue;
				}
				
				// Create if missing
				$isNew = false;
				if (! $valueRow) {
					$isNew = true;
					$valueRow = $values->createRow ();
					$valueRow->field_id = $field_id;
					$valueRow->item_id = $this->getItem ()->getIdentity ();
				}
				
				$valueRow->value = htmlspecialchars ( $value );
				$valueRow->save ();
				
			/*
        // Insert activity if being changed (and publish is enabled)
        if( !$isNew ) {
          $field = Engine_Api::_()->fields()->getFieldsMeta($this->getItem())->getRowMatching('field_id', $field_id);
          if( is_object($field) && !empty($field->publish) ) {
            $helper = new Fields_View_Helper_FieldValueLoop();
            $helper->view = Zend_Registry::get('Zend_View');
            $actionTable = Engine_Api::_()->getDbtable('actions', 'activity');

            if( $field->type )
            $actionTable->addActivity($this->getItem(), $this->getItem(), 'fields_change_generic', null, array(
              'label' => $field->label,
              'value' => $helper->getFieldValueString($field, $valueRow, $this->getItem()), //$value,
            ));
          }
        }
         * 
         */
			}
		}
		
		// Update search table
		Engine_Api::_ ()->getApi ( 'core', 'fields' )->updateSearch ( $this->getItem (), $values );
		
		// Fire on save hook
		Engine_Hooks_Dispatcher::getInstance ()->callEvent ( 'onFieldsValuesSave', array ('item' => $this->getItem (), 'values' => $values ) );
		
		// Regenerate form
		$this->generate ();
	}
	
	protected function _setFieldValues($values) {
		// Iterate over elements and apply the values
		foreach ( $this->getElements () as $key => $element ) {
			if (count ( explode ( '_', $key ) ) == 3) {
				list ( $parent_id, $option_id, $field_id ) = explode ( '_', $key );
				if (isset ( $values [$field_id] )) {
					$element->setValue ( $values [$field_id] );
				}
			}
		}
	}
	
	/* These are hacks to existing form methods */
	
	public function init() {
		$this->generate ();
	}
	
	public function isValid($data) {
		if (! is_array ( $data )) {
			require_once 'Zend/Form/Exception.php';
			throw new Zend_Form_Exception ( __CLASS__ . '::' . __METHOD__ . ' expects an array' );
		}
		$translator = $this->getTranslator ();
		$valid = true;
		
		if ($this->isArray ()) {
			$data = $this->_dissolveArrayValue ( $data, $this->getElementsBelongTo () );
		}
		
		// Changing this part
		$structure = $this->getFieldStructure ();
		$selected = array ();
		if (! empty ( $this->_topLevelId ))
			$selected [$this->_topLevelId] = $this->_topLevelValue;
		
		foreach ( $this->getElements () as $key => $element ) {
			$element->setTranslator ( $translator );
			
			$parts = explode ( '_', $key );
			if (count ( $parts ) !== 3) {
				continue;
			}
			
			list ( $parent_id, $option_id, $field_id ) = $parts;
			//if( !is_numeric($field_id) ) continue;
			

			$fieldObject = $structure [$key];
			
			// All top level fields are always shown
			if (! empty ( $parent_id )) {
				
				$parent_field_id = $parent_id;
				$option_id = $option_id;
				
				// Field has already been stored, or parent does not have option
				// specified, <del>or field is a heading</del>
				if (isset ( $selected [$field_id] ) || empty ( $selected [$parent_field_id] ) /* || !isset($data[$key])*/ ) {
					$element->setIgnore ( true );
					continue;
				}
				
				// Parent option doesn't match
				if (is_scalar ( $selected [$parent_field_id] ) && $selected [$parent_field_id] != $option_id) {
					$element->setIgnore ( true );
					continue;
				} else if (is_array ( $selected [$parent_field_id] ) && ! in_array ( $option_id, $selected [$parent_field_id] )) {
					$element->setIgnore ( true );
					continue;
				}
			}
			
			// This field is being used
			if (isset ( $data [$key] )) {
				$selected [$field_id] = $data [$key];
			}
			
			if ($element instanceof Engine_Form_Element_Heading) {
				$element->setIgnore ( true );
			} else if (! isset ( $data [$key] )) {
				$valid = $element->isValid ( null, $data ) && $valid;
			} else {
				$valid = $element->isValid ( $data [$key], $data ) && $valid;
			}
		}
		$this->_processedValues = $selected;
		// Done changing
		

		foreach ( $this->getSubForms () as $key => $form ) {
			$form->setTranslator ( $translator );
			if (isset ( $data [$key] )) {
				$valid = $form->isValid ( $data [$key] ) && $valid;
			} else {
				$valid = $form->isValid ( $data ) && $valid;
			}
		}
		
		$this->_errorsExist = ! $valid;
		return $valid;
	}
}